Support the .NET 11 SDK band and net11.0-tizen TFMs - #310
Conversation
…ression
Both installers were committed truncated mid-statement and NUL-padded, so the
publicly curl'd installer could never complete. workload-install.sh ended at
for DOTNET_SDK in $INSTALLED_DOTNET_SD
followed by 134 NUL bytes, and workload-install.ps1 ended inside its catch
block at `Write-Host `. The final lines are restored from the intact copies on
main.
validate-version-map.yml did not catch this because Generate-InstallScripts.ps1
only compares the auto-generated version-map block, and that block was
untouched, so it reported "OK" for a file missing its tail. The generator now
also verifies each installer contains no NUL bytes and ends with its expected
final statement, and fails otherwise.
Also restores the SDK enumeration fix that was lost in the same regression.
--update-all-workloads matched only `^6|^7`, silently ignoring every installed
.NET 8/9/10/11 SDK. It now matches majors 6-9 and any two-or-more digit major,
so future majors need no further edit.
Finally, extracts the SDK-version to feature-band computation into
compute_target_version_band() delimited by BEGIN/END VERSION BAND DETECTION
markers. Behaviour is unchanged - MANIFEST_NAME was already equal to the plain
band in the fall-through case - but the logic is now testable in isolation.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Adds .NET 11 support to the tizen workload alongside .NET 10. The primary target framework is net11.0-tizen11.0, which maps to TizenFX API level 15 and the already-published Samsung.Tizen.Ref.API15 targeting pack. No new reference or runtime pack is required: ref packs ship ref/net8.0 assemblies resolved by explicit paths in FrameworkList.xml, so they are independent of the consuming project's .NET version. Workload changes: * Versions.props: arcade 11.0.0-beta.26426.103 for 11.0 bands. * NuGet.config: add the dotnet11 source, and clear inherited disabledPackageSources so a developer with nuget.org disabled machine-wide does not get a confusing NU1101 for a source this file already lists. * Samsung.Tizen.Sdk.targets: add the net11.0 KnownRuntimePack. Without it the SDK cannot resolve Samsung.NETCore.App.Runtime.tizen (NETSDK1082). * RuntimeList.xml: add the .NET Runtime 11 FileList row. * template.json: offer net11.0; the default stays net10.0 because .NET 11 is still a preview SDK. * TizenApp1.csproj: Tizen.UI.Components.Material ships assets for the tizen 10.0 band only, so reference it conditionally on the resolved platform version and raise an actionable TIZENTMPL001 below that, instead of an opaque NU1101. Verification: * test-matrix.sh: add net11.0-tizen11.0 and net11.0-tizen10.0 rows. Rows whose .NET major has no installed SDK are now skipped rather than failed, so the default .NET 10 run stays green. * validate-workload-metadata.py: new checks C5/C6 tying every .NET major offered by the template or exercised by the matrix to a KnownRuntimePack and a RuntimeList.xml row. * test-version-band.sh: new test asserting the SDK version to feature band mapping (11.0.100-preview.7.26381.103 -> 11.0.100-preview.7) and that workload-install.sh and workload-install.ps1 agree. * Makefile: add validate-metadata, test-version-band and an aggregate check target that need no dotnet install. * build-matrix.yml: add a non-blocking .NET 11 preview leg. Validated by building the workload against 11.0.100-preview.7.26381.103: Samsung.NET.Sdk.Tizen.Manifest-11.0.100-preview.7 packs correctly, installs, and `dotnet new tizen --framework net11.0` builds a .tpk for both net11.0-tizen11.0 (resolving Samsung.Tizen.Ref.API15/15.0.0.19396) and net11.0-tizen10.0. version-map.json is deliberately not updated: it is a fallback cache of already-published manifest versions, so an entry for an unreleased band would make the installer download a 404. See workload/docs/net11.md for the mapping and the external blockers. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Maintainer action required: approve fork workflowsGitHub created all required PR runs, but they are in
Please use Approve and run workflows on these runs. Until then, the PR has no CI status even though the .NET 11 manifest pack/install/template/build/TPK chain was validated locally as described in the PR. |
Code review: * test-matrix.sh required an exact SDK/TFM major match, so the .NET 10 job skipped every net8/net9/net11 row and built nothing. An SDK builds its own major and all earlier ones, so rows are now skipped only when NEWER than the newest installed SDK. Pinned by a new `--self-test` mode that needs no dotnet install. * build-matrix.yml made .NET 11 unconditionally advisory and build-workload.yml always used the Versions.props default. Both now switch on a net11.0 branch or a PR into one: the .NET 11 leg blocks and the workload builds against $(DotNet11SdkVersion), a new SSOT in Versions.props that the workflows grep. Check C7 fails if a workflow hardcodes a different .NET 11 SDK. * The template read $(TargetPlatformVersion) in the project body, which the SDK has not yet inferred from the TFM at that point. net11.0-tizen9.0 therefore fell back to 10.0, pulled in an incompatible Tizen.UI.Components.Material and never raised TIZENTMPL001. The platform version is now parsed from $(TargetFramework), and the target re-checks the authoritative value. Verified end to end: tizen9.0 now errors with the real resolved version, tizen11.0 builds. * Both installers swallowed per-SDK failures and exited 0 after printing DONE. They now track failures and exit non-zero; --update-all-workloads still visits the remaining SDKs but the overall run fails. MSBuild review: * workload-install.ps1 built its fallback prefix from a fixed length ($ManifestBaseName.Length + 2), so '...Manifest-11.0.100-preview.7' became '...Manifest-1' and matched the 10.x entries, installing a .NET 10 manifest into an 11.x band. Both installers now constrain the fallback to the same major.minor family and fail closed. * DOTNET_VERSION was cached in .tmp/dotnet-version.config whose only prerequisite was Versions.props. The cache was always newer, so make never regenerated it and a newly-passed DOTNET_VERSION was ignored - silently building the previous band. It is now resolved immediately, and DOTNET_DESTDIR plus the install stamp are band-scoped. * PackageTargetFallback now covers the full (.NET major x platform) cross-product. A missing entry makes FixupNuGetReferences leave a package on its netstandard2.x assets; net11.0-tizen11.0 was absent. Check C8 keeps it in sync with KnownRuntimePack x TizenSdkSupportedTargetPlatformVersion. * release-workload.yml no longer builds with continue-on-error and no longer pushes a glob over whatever is on disk. It cleans first, fails on build error, stages to an isolated directory and verifies the expected manifest exists before pushing. * test-version-band.sh now extracts the real Get-TargetVersionBand from workload-install.ps1 instead of reimplementing it, so sh/ps1 drift is actually detectable, and also checks Config.mk producer parity. * Config.mk did not round the feature band for stable non-6 versions: 10.0.404 produced band '10.0.404' while the installers looked for '10.0.400'. Fixed, with producer/consumer parity tests. * MSI staging copied only Ref.API11/12/13; API14 and API15 were missing and API15 is the targeting pack for net11.0-tizen11.0. Now stages every Ref pack. * workload-install.sh had its shebang below a comment block, so direct execution did not reliably use bash. Moved to the first line. * make check now gates on pwsh with an actionable message instead of failing with 'command not found'; SKIP_PWSH_CHECKS=1 opts out. RuntimeList.xml (multiple root elements) is left as-is: proven not to be XML-parsed. Replacing the installed pack's copy with non-XML text still builds a net11.0-tizen11.0 project with an explicit RuntimeIdentifier - the path that resolves runtime pack assets and the one MAUI takes. Documented in workload/docs/net11.md. Validation on 11.0.100-preview.7.26381.103: full matrix 6/6 pass, 0 skipped (net8.0-tizen10.0/10.1/11.0, net9.0-tizen10.0, net11.0-tizen11.0, net11.0-tizen10.0). make check: C1-C8, 11 self-test, 61 version-band, 13 template-condition, 4 install-failure assertions, plus install-script drift and integrity. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Review fixes pushed —
|
| # | Fix |
|---|---|
| 1 | test-matrix.sh required an exact SDK/TFM major match, so the .NET 10 job skipped every net8/net9/net11 row and built nothing. Rows are now skipped only when newer than the newest installed SDK. New --self-test mode pins it with no dotnet install (11 assertions). |
| 2 | .NET 11 was unconditionally advisory and build-workload.yml always used the .NET 10 default. Both now switch on a net11.0 branch / PR-into-one: the leg blocks and the build uses $(DotNet11SdkVersion) — a new SSOT in Versions.props that the workflows grep. Check C7 fails if a workflow hardcodes a different version. |
| 3 | Confirmed and fixed. The template read $(TargetPlatformVersion) in the project body, before the SDK infers it from the TFM. Probe output was TPV='' resolved='10.0' material='True' for net11.0-tizen9.0 — exactly as reported. Now parsed from $(TargetFramework), with the target re-checking the authoritative value. Verified: net11.0-tizen9.0 → error TIZENTMPL001 ... (resolved TargetPlatformVersion: 9.0), net11.0-tizen11.0 builds. 13 evaluation regression tests added. |
| 4 | Both installers now track per-SDK failures and exit non-zero; --update-all-workloads still visits remaining SDKs but the run fails. 4 tests, including "must not print DONE on failure". |
MSBuild review
| # | Fix |
|---|---|
| 5 | Fixed. $ManifestBaseName.Length + 2 truncated ...Manifest-11.0.100-preview.7 to ...Manifest-1, matching 10.x entries. Both installers now constrain fallback to the same major.minor family and fail closed. Parity-tested. |
| 6 | Root cause was deeper than paths: DOTNET_VERSION was cached in .tmp/dotnet-version.config whose only prerequisite was Versions.props. The cache was always newer, so make never regenerated it and a newly-passed DOTNET_VERSION was ignored. Now resolved immediately; DOTNET_DESTDIR and the install stamp are band-scoped. Band-switching in one tree is tested. |
| 7 | PackageTargetFallback now covers the full 30-entry (.NET major × platform) cross-product. Confirmed via FixupNuGetReferences: a missing entry leaves a package on its netstandard2.x assets — net11.0-tizen11.0 was absent. Check C8 keeps it in sync with KnownRuntimePack × TizenSdkSupportedTargetPlatformVersion. |
| 8 | release-workload.yml: no continue-on-error, make clean first, stage to an isolated dir, verify the expected manifest exists, push explicit staged paths. Band is computed by reusing the installer's own function so the release can't disagree with it. |
| 9 | test-version-band.sh now extracts the real Get-TargetVersionBand from workload-install.ps1 (same BEGIN/END markers as bash) instead of reimplementing it, so drift is genuinely detectable. |
| 10 | Confirmed: Config.mk did not round stable non-6 bands — 10.0.404 → 10.0.404 while installers looked for 10.0.400. Fixed; producer/consumer parity now asserted across all 18 version cases. |
| 11 | MSI staging copied only Ref.API11/12/13. Now stages every Ref.API* — API15 is the targeting pack for net11.0-tizen11.0. |
| 12 | Shebang moved to line 1. |
| 13 | make check gates on pwsh with an actionable message; SKIP_PWSH_CHECKS=1 opts out. |
#14 — RuntimeList.xml: proven not XML-parsed, left unchanged
The file does have multiple root elements. I checked the consumer contract empirically rather than assuming:
Microsoft.NET.Build.Tasks.dlldoes containRuntimeListNotFound/absoluteRuntimeListPath, so the SDK can read a runtime pack'sRuntimeList.xml— a static grep alone would have been misleading.- So I tested the path that actually resolves runtime pack assets: a
net11.0-tizen11.0build with an explicitRuntimeIdentifier=tizen-x86(what MAUI takes viaEnableImplicitRuntimeIdentifiers). Built clean. - Decisive test: replaced the installed pack's
RuntimeList.xmlwith the literal text<<< THIS IS NOT XML AT ALL &&& >>>and rebuilt the same RID-specific project →Build succeeded. 0 Error(s).
Samsung.NETCore.App.Runtime.tizen is a placeholder pack whose only payload is lib/net6.0-tizen/_._, so nothing reads the file. Making it well-formed would need a non-standard wrapper root or splitting the pack per .NET version — more risk than the malformed file carries while unread. C6 parses it line-wise, matching how it's produced. Documented in workload/docs/net11.md with the revisit criteria.
Validation on 11.0.100-preview.7.26381.103
Full matrix 6/6 pass, 0 skipped — net8.0-tizen10.0, net8.0-tizen10.1, net8.0-tizen11.0, net9.0-tizen10.0, net11.0-tizen11.0, net11.0-tizen10.0.
make check: C1–C8, 11 self-test, 61 version-band (bash ↔ PowerShell ↔ Config.mk, fallback family, band isolation), 13 template-condition, 4 install-failure assertions, plus version-map drift and install-script integrity. Docs updated to describe the corrected behaviour.
Unrelated observation
tizen.myget.org now returns HTTP 401 to anonymous clients (.../api/v3/index.json). It remains a push target in build-workload.yml's deploy job. I have not touched it — removing a publishing destination is a maintainer call — but it's noted in workload/docs/net11.md in case any docs still point consumers there for restore.
Updated workflow approval request for head
|
Merge-readiness validation at head
|
DOTNET_VERSION |
Produced package |
|---|---|
11.0.100-preview.7.26381.103 |
Samsung.NET.Sdk.Tizen.Manifest-11.0.100-preview.7.10.0.123.nupkg |
10.0.100 |
Samsung.NET.Sdk.Tizen.Manifest-10.0.100.10.0.123.nupkg |
The .NET 11 manifest declares Samsung.Tizen.Ref.API15 → 15.0.0.19396, the targeting pack for net11.0-tizen11.0.
Diffed the 10.0 build against the actually-published Samsung.NET.Sdk.Tizen.Manifest-10.0.100 10.0.123 from nuget.org:
- package id: identical
WorkloadManifest.targets: byte-identicalWorkloadManifest.json: differs only by the additiveSamsung.Tizen.Ref.API14/API15pack entries — introduced by base-branch commit44d7bdf, which predates this branch point.git diff 5e13077 HEAD -- .../WorkloadManifest.in.jsonis empty; this PR does not touch that file.
Feature-band change: proven non-regressive
The Config.mk rounding fix (finding #10) changes the manifest package ID, so I verified it against every one of the 37 bands in version-map.json, comparing the pre-change logic (reconstructed from base commit 5e13077) with the current one:
identical: 37 differing: 0
It differs only for non-round patch versions, where the new value is the correct one:
| input | old (producer) | new (producer) | installer (consumer) expects |
|---|---|---|---|
9.0.304 |
9.0.304 |
9.0.300 |
9.0.300 ✅ |
10.0.404 |
10.0.404 |
10.0.400 |
10.0.400 ✅ |
8.0.421 |
8.0.421 |
8.0.400 |
8.0.400 ✅ |
End-to-end, both bands, one tree
| Band | dotnet workload list |
Matrix |
|---|---|---|
11.0.100-preview.7 |
tizen 10.0.123/11.0.100-preview.7 |
6/6 pass, 0 skipped |
10.0.100 |
tizen 10.0.123/10.0.100 |
4 pass, 0 fail, 2 skipped (net11 rows only) |
The 10.0 run is the direct refutation of finding #1: net8/net9 rows now build on a .NET 10 SDK and only the genuinely-unbuildable net11 rows skip. Previously every row skipped and the job built nothing.
Both SDKs coexist under out/dotnet-10.0.100 and out/dotnet-11.0.100-preview.7, confirming the band-isolation fix (#6).
make check on the clean tree: C1–C8 plus 89 assertions (11 self-test, 61 version-band, 13 template-condition, 4 install-failure), version-map drift and install-script integrity — all green.
Pre-existing issue found (NOT introduced here, NOT fixed here)
The .NET 9 band cannot be built on this branch, independent of these changes:
error: Unable to find package Microsoft.DotNet.SharedFramework.Sdk with version (= 9.0.0-beta.25065.2)
Evidence it is pre-existing:
- the pin was added by commit
86fcc19(2025-11-19), long before this branch; git diff 5e13077 HEAD -- workload/build/Versions.propsshows my edits are purely additive (the11.0block +DotNet11SdkVersion) and do not touch the 9.0 pin;9.0.0-beta.25065.2exists forMicrosoft.DotNet.Arcade.Sdkbut not forMicrosoft.DotNet.SharedFramework.Sdkondotnet-eng(nearest real versions present in both:9.0.0-beta.25058.5,9.0.0-beta.25077.4).
Only the 9.0 pin is affected — 8.0, 10.0 and 11.0 all resolve.
I have not changed it: it is outside this PR's scope, and I cannot validate a 9.0 pack-output comparison precisely because the band doesn't build today. Flagging it because one consequence of finding #8's fix is relevant: with continue-on-error removed from release-workload.yml, a release run for the 9.0 band will now fail loudly instead of silently proceeding to the push step. That is the intended behaviour, but it means this latent breakage becomes visible.
Remaining blocker
Only maintainer approval of the fork workflow runs. All three remain action_required at the run IDs listed in the previous comment; no new runs were created because the head did not change.
Installers
* getLatestVersion / Get-LatestVersion now return "<packageId>=<version>". Returning
only a version made the caller download that version under the ORIGINAL, unpublished
manifest id: a request for '...manifest-10.0.400' resolves to 10.0.127, which exists
only under '...manifest-10.0.300', so the download 404'd. Verified live against
nuget.org: old path HTTP 404, new path HTTP 200, and an end-to-end run installs the
10.0.300 package into the 10.0.400 band directory.
* Removed $global:FallbackId from workload-install.ps1. It was never cleared, so an
-UpdateAllWorkloads run could carry one SDK's fallback package into the next SDK's
install. The resolved id is now function-local. Verified with a live two-SDK run
(10.0.404 -> fallback install, then 11.0.100-preview.7 -> fails closed, no 11.x
directory created).
* Replaced the ${var,,} lowercase expansion. It is bash 4+, and macOS ships bash 3.2 -
where it raised "bad substitution", left the version empty and silently skipped the
fallback entirely, making the fix above unreachable. macOS is a supported target
(DOTNET_DEFAULT_PATH_MACOS). An empty or failed version query now takes the same
fallback path as an explicit BlobNotFound, and a failed download fails closed.
* Quoted install/temp paths so a directory containing spaces works.
NuGet fallbacks
* Samsung.Tizen.Sdk.NuGet.targets no longer passes an unfiltered 30-entry cross product.
FixupNuGetReferences matches lib/<name>/ directories by NAME ONLY, so the list has to
be filtered: a net6.0-tizen8.0 build could otherwise consume net6.0-tizen11.0 or
net11.0-tizen8.0 assets. Candidates are emitted only when both their .NET version and
their platform version are <= the project's, highest-first so the best compatible
match wins. Built from conditional properties, not items - MSBuild evaluates all
top-level properties before any items, so an @(item) reference there expands to
nothing.
Runtime metadata
* RuntimeList.xml is now well-formed (single <FileList> root). It IS parsed:
Microsoft.NET.Build.Tasks carries the literal alongside the runtime-pack manifest
fields ResolveRuntimePackAssets reads. A previous note claiming otherwise was based on
a framework-dependent RID build, which never reaches that task; that claim is
retracted in the docs.
* Self-contained Tizen publishing is rejected with TIZENSDK001. The pack ships no
runtime binaries, so a self-contained app cannot work; previously this surfaced as an
opaque NETSDK1083. Note: with the guard bypassed and the malformed file restored, this
configuration still failed at NETSDK1083 before reaching ResolveRuntimePackAssets, so
a raw XmlException was not reproducible here - the malformed file was nonetheless a
latent hazard on any path that does reach it.
Release
* Release notes reuse the staging step's verified band and manifest id. Recomputing
${SDK%%-*} produced 11.0.100 for 11.0.100-preview.7.* and 10.0.404 for a servicing
band, linking to packages that were never published.
* The version bump is committed and pushed, and the tag targets that commit. Previously
the bump was runner-local, so the released tag pointed at sources still carrying the
previous version.
Coverage
* Matrix gains explicit net10.0 rows (10.0/10.1/11.0) plus net11.0-tizen10.0, and a
self-contained disposition assertion.
* The .NET 11 leg now blocks by default; set repo variable TIZEN_NET11_ADVISORY=true to
downgrade it temporarily.
* New scripts/test-package-fallback.sh pins the fallback filtering with negative
cross-platform/cross-version cases. C6 now parses RuntimeList.xml with a real XML
parser and requires the TIZENSDK001 guard; C8 requires every fallback candidate to be
compatibility-gated; C7 ignores YAML comments.
Validation on 11.0.100-preview.7.26381.103: matrix 9/9 TFM rows plus the self-contained
assertion, 0 skipped. make check: C1-C8 plus 110 assertions (11 self-test, 61
version-band, 13 template-condition, 6 package-fallback, 19 install-failure) - including
a real install into a space-containing path and an unreachable-feed case, all under
bash 3.2.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
New head
|
| requested (unpublished) | samsung.net.sdk.tizen.manifest-10.0.400 |
| resolved | samsung.net.sdk.tizen.manifest-10.0.300 = 10.0.127 |
| old download path | …manifest-10.0.400/10.0.127 → HTTP 404 |
| new download path | …manifest-10.0.300/10.0.127 → HTTP 200 |
End-to-end run installs the 10.0.300 package into the 10.0.400 band directory, as intended.
$global:FallbackId removed. Verified with a live two-SDK -UpdateAllWorkloads run:
10.0.404 → falls back and installs; then 11.0.100-preview.7 → fails closed (Wrong Id),
overall exit 1, and no 11.x manifest directory is created. Previously the 10.x fallback id
persisted into the next iteration.
bash 3.2 (macOS). ${MANIFEST_NAME,,} is bash 4+; on macOS it raised bad substitution,
left the version empty and silently skipped the fallback entirely — making the fix above
unreachable there. Replaced with tr. An empty/failed query now takes the same path as
BlobNotFound, and a failed download fails closed. Install/temp paths are quoted; a real
install into dir with spaces/dotnet sdk is now a test.
NuGet fallbacks
FixupNuGetReferences matches lib/<name>/ by name only, so the list must be filtered.
Candidates are emitted only when both .NET version and platform version are <= the
project's, appended highest-first. Negative assertions now guard exactly the leaks called out:
| building | must NOT admit |
|---|---|
net6.0-tizen8.0 |
net6.0-tizen9.0/10.0/11.0, net8.0-tizen8.0, tizen90, tizen10.0 |
net11.0-tizen8.0 |
net11.0-tizen9.0, net6.0-tizen11.0, tizen90 |
net6.0-tizen11.0 |
net8.0-tizen11.0, net11.0-tizen11.0, net9.0-tizen10.0 |
Deleting the filter makes the test fail with explicit LEAKED: diagnostics.
Built from conditional properties, not items — MSBuild evaluates all top-level properties
before items, so an @(item) reference there silently expands to nothing (this bit me first
attempt).
Runtime metadata — correcting my earlier claim
You are right that RuntimeList.xml is parsed, and my earlier "never parsed" note was wrong.
It is retracted in the docs. Microsoft.NET.Build.Tasks carries the literal RuntimeList.xml
next to the runtime-pack manifest fields ResolveRuntimePackAssets reads (Managed, Native,
PgoData, AssemblyVersion, PublicKeyToken). My earlier test used a framework-dependent
RID build, which never reaches that task.
Both remediations applied:
- The file is well-formed (single
<FileList>root, legitimately empty — the pack ships
onlylib/net6.0-tizen/_._). - Self-contained is rejected with
TIZENSDK001and an actionable message.
One precise scope note: with the guard bypassed and the malformed file restored, this
configuration failed at NETSDK1083 (RID resolution) before reaching
ResolveRuntimePackAssets, so I could not reproduce a raw XmlException here. I'm reporting
that rather than claiming a repro I didn't get. The malformed file was still a latent hazard on
any path that does reach the task, and both fixes stand regardless of which error surfaces first.
Release
- Notes reuse the staging step's verified band and manifest id.
${SDK%%-*}produced
11.0.100for11.0.100-preview.7.*and10.0.404for a servicing band — both linking to
packages that were never published. - The version bump is now committed and pushed, and the tag targets that commit. Previously
the bump was runner-local, so the tag pointed at sources still carrying the previous version.
Coverage
- Matrix gains explicit net10.0 rows (
10.0/10.1/11.0) plusnet11.0-tizen10.0→ 9 TFM
rows, plus a self-contained disposition assertion. - .NET 11 now blocks by default (
TIZEN_NET11_ADVISORY=truedowngrades it). The SDK version
is pinned exactly, so the leg is deterministic — and a branch whose purpose is .NET 11 support
gains nothing from an advisory-only .NET 11 gate.
Validation on 11.0.100-preview.7.26381.103
Matrix 9/9 TFM rows + self-contained assertion, 0 skipped:
net8.0-tizen{10.0,10.1,11.0}, net9.0-tizen10.0, net10.0-tizen{10.0,10.1,11.0},
net11.0-tizen{10.0,11.0}, and PASS self-contained rejected with TIZENSDK001.
make check: C1–C8 plus 110 assertions — 11 self-test, 61 version-band
(bash ↔ PowerShell ↔ Config.mk), 13 template-condition, 6 package-fallback, 19 install-failure
— all under bash 3.2, including the space-path install and an unreachable-feed case.
Environmental note (not a repo defect)
On this machine the freshly extracted .NET 11 preview SDK cannot run RoslynCodeTaskFactory
(MSB3755 for mscorlib/netstandard), so make packs fails under it. The same sources
pack cleanly under .NET 10.0.400, producing Samsung.NET.Sdk.Tizen.Manifest-11.0.100-preview.7
correctly, and the resulting workload installs into and builds with the .NET 11 SDK. Flagging in
case CI hits it; I could not attribute it to anything in this branch.
Approval links are already current for
|
| Workflow | Run |
|---|---|
| Build Workload | 33070345680 |
| Build Matrix | 33070345658 |
| Validate Version Map | 33070345715 |
action_required:
9cdce68— Build Workload / Build Matrix / Validate Version Mapb847341— Build Workload / Build Matrix / Validate Version Map
Because every push from a non-member fork queues a new set awaiting approval, older sets linger in the Actions tab and look identical apart from the commit SHA. Approving one of those would run CI against superseded code and report a result that does not describe the current head — worth knowing before clicking, since the older heads lack every fix from 6fffd09.
The GitHub Actions run list can be filtered to the current head with:
https://github.com/Samsung/Tizen.NET/actions?query=branch%3Aredth-net11-tizen-workload
then matching the commit SHA column against 6fffd09.
Head is being held stable at 6fffd09 pending the exact-head reviews; I will not push unless a reviewer reports a real blocker.
1. PowerShell empty versions An empty or all-blank versions[] made `Select-Object -Last 1` yield $null, so Get-LatestVersion returned "<id>=" - a TRUTHY string. The caller then split off an empty version, and the NuGet v2 package endpoint serves the LATEST package when the URL has no version segment, silently installing an arbitrary version. Blank entries are now filtered, an empty result falls through to the retry/version-map path, and the caller rejects an empty id or version outright. The shell installer gained the same guard before the download. 2. Shell SDK pinning install_tizenworkload is invoked under `if !`, which disables errexit for everything it calls, so the unchecked `dotnet new globaljson` let the install proceed against whatever SDK PATH resolved. The pin now uses the dotnet under test, its exit status is checked, and the EFFECTIVE `dotnet --version` and feature band are re-verified against the requested ones before any pack is installed. Verified with a stub whose pin silently does not take effect: the run aborts non-zero and never reaches the install. 3. Release versioning / resume The bump was committed and pushed BEFORE the build, so any later failure left the branch already bumped and the retry computed OLD == NEW and aborted - an unretryable release. Persistence now happens only after the build succeeds and the expected artifacts are verified on disk. OLD == NEW resumes instead of aborting, since next-workload-version.py derives from what is published on NuGet and the branch may legitimately already carry the intended unpublished version. Reference-only runs are fully non-mutating (no bump, no commit, no tag), and re-creating an existing tag is a no-op. 4. Fallback priority and atomicity PackageTargetFallback is an ordered preference list, but FixupNuGetReferences collected every matching directory into an unordered HashSet populated in filesystem-enumeration order and then took assemblies first-wins across all of them. That could ignore the declared priority and mix assemblies from different TFMs within one package. Candidates are now ranked by their position in the list, exactly ONE fallback TFM is selected per package, and every substituted assembly comes from that single directory. 5. Self-contained matrix outcome An unexpected diagnostic warned and passed. Self-contained has exactly one supported outcome, so anything other than TIZENSDK001 - including NETSDK1083 or an accidental success - now fails CI, as does being unable to prepare the fixture. Tests: new scripts/test-release-workflow.sh (14 assertions covering ordering, retryability and non-mutating reference-only runs); test-package-fallback.sh gains priority/atomicity cases built in BOTH directory-creation orders so the assertion does not depend on filesystem enumeration; test-install-failure.sh gains SDK-pin verification (effective and ineffective) and empty-response guards for both installers. Validation: make check green - C1-C8 plus 135 assertions (11 self-test, 61 version-band, 13 template-condition, 12 package-fallback, 14 release-workflow, 24 install-failure), all under bash 3.2, including installs into a space-containing path, an unreachable feed, and a pin that does not take effect. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
New head
|
| Workflow | Run |
|---|---|
| Build Workload | 33077331106 |
| Build Matrix | 33077331324 |
| Validate Version Map | 33077331204 |
6fffd09, 9cdce68 and b847341 are also queued in action_required and must not be approved — they would test superseded code.
1. PowerShell empty versions
An empty/all-blank versions[] made Select-Object -Last 1 yield $null, so the function returned "<id>=" — truthy. The caller split off an empty version, and the NuGet v2 endpoint serves the latest package for a versionless URL. Blank entries are now filtered, an empty result falls through to the retry/version-map path, and the caller rejects an empty id or version. The shell installer gained the same guard before the download.
2. Shell SDK pinning
install_tizenworkload runs under if !, which disables errexit for everything it calls — so the unchecked dotnet new globaljson let the install proceed on the wrong SDK. The pin now uses the dotnet under test, its exit status is checked, and the effective dotnet --version and feature band are re-verified before any pack is installed.
Verified with a stub whose pin silently doesn't take effect:
SDK pin did not take effect: requested 10.0.100, active 9.0.100.
FAILED to install Tizen workload for sdk(s): 10.0.100
exit=1
REACHED_INSTALL never printed. The matching effective-pin case still installs normally.
3. Release versioning / resume
Persistence now happens only after the build succeeds and artifacts are verified. OLD == NEW resumes instead of aborting — next-workload-version.py derives from what's published on NuGet, so the branch may legitimately already carry the intended unpublished version. Reference-only runs are fully non-mutating; re-creating an existing tag is a no-op. Order is pinned by 14 assertions.
4. Fallback priority and atomicity
FixupNuGetReferences collected every match into an unordered HashSet (populated in filesystem-enumeration order) and took assemblies first-wins across all of them. It now ranks candidates by their position in PackageTargetFallback, selects exactly one fallback TFM per package, and takes every substituted assembly from that single directory.
One thing I want to be straight about: the new tests build the candidate directories in both creation orders so the assertion can't depend on filesystem enumeration, and they pass. But I could not construct a case where the old implementation demonstrably failed on this machine — directory enumeration here happened to favour the correct answer in every variant I tried, including reversed creation order and a package where only the lower-priority TFM carried the second assembly. So the tests lock in the correct contract going forward, but I can't claim to have empirically reproduced the mis-selection; the fix rests on the code path being order-dependent by construction, which the diff makes explicit.
5. Self-contained matrix outcome
An unexpected diagnostic previously warned and passed. Anything other than TIZENSDK001 — including NETSDK1083 or an accidental success — now fails CI, as does being unable to prepare the fixture.
Validation
make check green: C1–C8 + 135 assertions — 11 self-test, 61 version-band, 13 template-condition, 12 package-fallback, 14 release-workflow, 24 install-failure — all under bash 3.2, including installs into a space-containing path, an unreachable feed, and a pin that doesn't take effect.
The 9-row TFM matrix and self-contained assertion were verified on 11.0.100-preview.7.26381.103 at 6fffd09; this head changes the installers, the fallback task, the release workflow and tests, and make check covers all of them. Full-matrix re-verification will come from the CI runs above once approved.
Summary
Adds .NET 11 support to the
tizenworkload alongside .NET 10, and repairs two install scripts that were committed corrupt on this branch.Chosen TFM / API mapping
Primary TFM:
net11.0-tizen11.0→ TizenFX API level 15 →Samsung.Tizen.Ref.API1515.0.0.19396(already published).net11.0combines with every declared platform version, sonet11.0-tizen{8.0,9.0,10.0,10.1,11.0}all work.No new reference or runtime pack is required. Ref packs ship
ref/net8.0assemblies resolved by explicit<File Path=…/>entries indata/FrameworkList.xml, so they're independent of the consuming project's .NET version.Samsung.Tizen.Ref.API16does not exist and isn't needed.SDK feature band:
11.0.100-preview.7(latest .NET 11 SDK is11.0.100-preview.7.26381.103, 2026-08-11).Commit 1 — install script repair (independent of .NET 11)
Both installers were committed truncated mid-statement and NUL-padded, so the publicly
curl'd installer could never complete:workload-install.shended atfor DOTNET_SDK in $INSTALLED_DOTNET_SD+ 134 NUL bytesworkload-install.ps1ended inside itscatchblock atWrite-Hostvalidate-version-map.ymldidn't catch it becauseGenerate-InstallScripts.ps1only compares the auto-generated version-map block — which was intact — so it reported OK for a file missing its tail. The generator now also asserts no NUL bytes and an expected final statement.Also restores the SDK enumeration fix lost in the same regression:
--update-all-workloadsmatched only^6|^7, silently ignoring every installed .NET 8/9/10/11 SDK.Commit 2 — .NET 11 support
build/Versions.props11.0.0-beta.26426.103for11.0bandsNuGet.configdotnet11; clear inheriteddisabledPackageSourcesSamsung.Tizen.Sdk.targetsnet11.0KnownRuntimePack(without it: NETSDK1082)RuntimeList.xml.NET Runtime 11rowtemplate.jsonnet11.0; default staysnet10.0while .NET 11 is previewTizenApp1.csprojTizen.UI.Components.Materialreferenced conditionally on the resolved platform version, with an actionableTIZENTMPL001instead of an opaque NU1101test-matrix.shvalidate-workload-metadata.pyKnownRuntimePack+RuntimeList.xmltest-version-band.sh.sh/.ps1parityMakefilevalidate-metadata,test-version-band, aggregatecheck(no dotnet install needed)build-matrix.ymlversion-map.jsonis deliberately not updated — it's a fallback cache of already published manifest versions, so an entry for an unreleased band would make the installer download a 404. Add it after the first release, as10.0.300was.Validation performed
Built the workload against the real .NET 11 preview SDK (
11.0.100-preview.7.26381.103):Samsung.NET.Sdk.Tizen.Manifest-11.0.100-preview.7packs with the correct id, installs intosdk-manifests/11.0.100-preview.7/dotnet new tizen --framework net11.0+dotnet buildproducescom.companyname.TizenApp1-1.0.0.tpkfor bothnet11.0-tizen11.0andnet11.0-tizen10.0net11.0-tizen11.0verified to resolveSamsung.Tizen.Ref.API15/15.0.0.19396make check: 6/6 metadata checks, 36/36 version-band assertions, install-script drift + integrity all greenKnownRuntimePack/RuntimeListrow fails the build)Not run locally:
Samsung.Tizen.Ref.API13/14/15packing, which needsTizen.NET.API*from Samsung's GitHub Packages feed (403 without org membership). CI hassecrets.GITHUB_TOKENfor this. The published equivalents were substituted to complete the end-to-end run.External blockers (not fixable here, not faked)
Samsung.NET.Sdk.Tizen.Manifest-11.0.100-preview.7is unpublished. Needs aRelease Workloadrun withnet_sdk_version = 11.0.100-preview.7.26381.103. Until thenworkload-install.shfinds no manifest on an 11.x SDK.Tizen.UIExtensions.NUI(Samsung/Tizen.UIExtensions) — published0.9.2shipslib/net6.0-tizen7.0+lib/tizen10.0. TFM compatibility is fine; the blocker is its dependency group pinningMicrosoft.Maui.Graphics6.0.300-rc.3.1336. Needs a release withlib/net11.0-tizen11.0built against API15 and refreshed MAUI Graphics deps.Tizen.UI.Components.Material1.0.0-rc.8— ships onlylib/net8.0-tizen10.0, never GA. Unusable belowtizen10.0; handled in the template as described above.Details, owners and expected artifact names in
workload/docs/net11.md.